﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../global/head.h"
#include "../xos/head.h"
#include "time_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

	static time_t g_t_time_zone_second_s = -1;
    static time_impl::POOL * pool_ptr = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    time_impl::time_impl()
    {
		init_data();
    }

    time_impl::~time_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int time_impl::get_addr( POOL *** pppPool, LIST *** pppList )
    {
		int ret = 0;
		if( pppPool )
		{
			*pppPool = &pool_ptr;
		}
		if( pppList )
		{
			*pppList = 0;
		}
		return ret;
    }

	// 
	// FILETIME and time(), F and T : F / 10000000 - 11644473600 = T
	// 
	// FILETIME is from 1601-01-01 00:00:00, time() is 1970-01-01 00:00:00
	//
	xos::xos_i64 time_impl::file_1601_to_time_1970( xos::xos_i64 iT )
	{
		return iT / 10000000 - 11644473600;
	}

	xos::xos_i64 time_impl::time_1970_to_file_1601( xos::xos_i64 iT )
	{
		return ( iT + 11644473600 ) * 10000000;
	}

	int time_impl::cal_time_zone_second()
	{
		int ret = 0;

		if( -1 != g_t_time_zone_second_s )
		{
			return 0;
		}

		struct tm tm1 = { 0 }, tm2 = { 0 };

		time_t t = time( 0 );

		time_t t1 = 0;
		time_t t2 = 0;

		localtime_s( &tm1, &t );
		gmtime_s( &tm2, &t );

		t1 = mktime( &tm1 );
		t2 = mktime( &tm2 );

		g_t_time_zone_second_s = t1 - t2;

		return ret;
	}

	int time_impl::init_data()
	{
		int ret = 0;

		memset( &m_tm, 0, sizeof( m_tm ) );
		cal_time_zone_second();

		return ret;
	}

    int time_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int time_impl::term()
    {
        int nRet = 0;
		init_data();
        return nRet;
    }

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 

	// 
	// 2018-01-30 05:05:30
	// 
	int time_impl::get_time_string_ymdhms( char * lpszTimeStr, int nSize, int * lpnRetLen )
	{
		int ret = 0;

		int len = sprintf_s( lpszTimeStr, nSize, "%04d-%02d-%02d %02d:%02d:%02d",
			m_tm.wYear,
			m_tm.wMonth,
			m_tm.wDay,
			m_tm.wHour,
			m_tm.wMinute,
			m_tm.wSecond );
		if( lpnRetLen )
		{
			*lpnRetLen = len;
		}

		return ret;
	}

	// 
	// 2018-01-30
	// 
	int time_impl::get_time_string_ymd( char * lpszTimeStr, int nSize, int * lpnRetLen )
	{
		int ret = 0;

		int len = sprintf_s( lpszTimeStr, nSize, "%04d-%02d-%02d",
			m_tm.wYear,
			m_tm.wMonth,
			m_tm.wDay );
		if( lpnRetLen )
		{
			*lpnRetLen = len;
		}

		return ret;
	}

	// 
	// 12:03:23
	// 
	int time_impl::get_time_string_hms( char * lpszTimeStr, int nSize, int * lpnRetLen )
	{
		int ret = 0;

		int len = sprintf_s( lpszTimeStr, nSize, "%02d:%02d:%02d",
			m_tm.wHour,
			m_tm.wMinute,
			m_tm.wSecond );
		if( lpnRetLen )
		{
			*lpnRetLen = len;
		}

		return ret;
	}

	// 
	// Wed, 28 Aug 2019 03:48:08 GMT
	// 
	int time_impl::get_time_string_gmt( char * lpszTimeStr, int nSize, int * lpnRetLen )
	{
		int ret = 0;

		time_t lt = ( time_t )get_wall_time_s();
		struct tm tm_s = { 0 };
		gmtime_s( &tm_s, &lt );
		int len = ( int )strftime( lpszTimeStr, nSize, "%a, %d %b %Y %X GMT", &tm_s );
		if( lpnRetLen )
		{
			*lpnRetLen = len;
		}

		return ret;
	}

	int time_impl::get_time_name_ymdhms( char * lpszTimeStr, int nSize, int * lpnRetLen )
	{
		int ret = 0;

		int len = sprintf_s( lpszTimeStr, nSize, "%04d%02d%02d%02d%02d%02d",
			m_tm.wYear,
			m_tm.wMonth,
			m_tm.wDay,
			m_tm.wHour,
			m_tm.wMinute,
			m_tm.wSecond );
		if( lpnRetLen )
		{
			*lpnRetLen = len;
		}

		return ret;
	}

	int time_impl::get_time_name_ymd( char * lpszTimeStr, int nSize, int * lpnRetLen )
	{
		int ret = 0;

		int len = sprintf_s( lpszTimeStr, nSize, "%04d%02d%02d",
			m_tm.wYear,
			m_tm.wMonth,
			m_tm.wDay );
		if( lpnRetLen )
		{
			*lpnRetLen = len;
		}

		return ret;
	}

	int time_impl::get_time_name_hms( char * lpszTimeStr, int nSize, int * lpnRetLen )
	{
		int ret = 0;

		int len = sprintf_s( lpszTimeStr, nSize, "%02d%02d%02d",
			m_tm.wHour,
			m_tm.wMinute,
			m_tm.wSecond );
		if( lpnRetLen )
		{
			*lpnRetLen = len;
		}

		return ret;
	}

	xos_i64 time_impl::get_wall_time_s()
	{
		xos_i64 ret = 0;

		struct tm temptm = { 0 };

		temptm.tm_year = m_tm.wYear - 1900;
		temptm.tm_mon = m_tm.wMonth - 1;
		temptm.tm_mday = m_tm.wDay;
		temptm.tm_hour = m_tm.wHour;
		temptm.tm_min = m_tm.wMinute;
		temptm.tm_sec = m_tm.wSecond;

		ret = (xos_i64)mktime( &temptm );

		return ret;
	}

	int time_impl::get_milli_second()
	{
		int nRet = m_tm.wMilliseconds;
		return nRet;
	}

	// 
	// update time
	// 
	int time_impl::get_time()
	{
		int nRet = 0;

        SYSTEMTIME tm = { 0 };
        GetLocalTime( &tm );
        std::memcpy( &m_tm, &tm, sizeof( tm ) );

		return nRet;
	}

	// 
	// get time details
	// 
	int time_impl::get_year()
	{
		int nRet = m_tm.wYear;
		return nRet;
	}

	int time_impl::get_month()
	{
		int nRet = m_tm.wMonth;
		return nRet;
	}

	int time_impl::get_week()
	{
		int nRet = m_tm.wDayOfWeek;
		return nRet;
	}

	int time_impl::get_day()
	{
		int nRet = m_tm.wDay;
		return nRet;
	}

	int time_impl::get_hour()
	{
		int nRet = m_tm.wHour;
		return nRet;
	}

	int time_impl::get_minute()
	{
		int nRet = m_tm.wMinute;
		return nRet;
	}

	int time_impl::get_second()
	{
		int nRet = m_tm.wSecond;
		return nRet;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // set time details
    // 

	// 
	// 2018-01-30 05:05:30
	// 
	int time_impl::set_time_string_ymdhms( const char * lpszTimeStr )
	{
		int ret = 0;

		memset( &m_tm, 0, sizeof( m_tm ) );

		int y = 0;
		int m = 0;
		int d = 0;
		int H = 0;
		int M = 0;
		int S = 0;

		sscanf_s( lpszTimeStr, "%04d-%02d-%02d %02d:%02d:%02d", &y, &m, &d, &H, &M, &S );

		m_tm.wYear = (WORD)y;
		m_tm.wMonth = (WORD)m;
		m_tm.wDay = (WORD)d;
		m_tm.wHour = (WORD)H;
		m_tm.wMinute = (WORD)M;
		m_tm.wSecond = (WORD)S;

		return ret;
	}

	// 
	// 2018-01-30
	// 
	int time_impl::set_time_string_ymd( const char * lpszTimeStr )
	{
		int ret = 0;

		memset( &m_tm, 0, sizeof( m_tm ) );

		int y = 0;
		int m = 0;
		int d = 0;

		sscanf_s( lpszTimeStr, "%04d-%02d-%02d", &y, &m, &d );

		m_tm.wYear = (WORD)y;
		m_tm.wMonth = (WORD)m;
		m_tm.wDay = (WORD)d;

		return ret;
	}

	// 
	// Wed, 28 Aug 2019 03:48:08 GMT
	// 
	int time_impl::set_time_string_gmt( const char * lpszTimeStr )
	{
		int ret = 0;

		xos::i_crt * pCrt = 0;
		time_t t = 0;
		{
			g_pXos->create( xos::i_xos::XOS_OBJ_CRT, (void**)&pCrt );
		}
		{
			struct tm tm_s = { 0 };
			pCrt->strptime( lpszTimeStr, "%a, %d %b %Y %X GMT", &tm_s );
			t = mktime( &tm_s ) + g_t_time_zone_second_s;
		}
		set_wall_time_s( t );
		xos_stl::release_interface( pCrt );

		return ret;
	}

	int time_impl::set_time_name_ymdhms( const char * lpszTimeStr )
	{
		int ret = 0;

		memset( &m_tm, 0, sizeof( m_tm ) );

		int y = 0;
		int m = 0;
		int d = 0;
		int H = 0;
		int M = 0;
		int S = 0;

		sscanf_s( lpszTimeStr, "%04d%02d%02d%02d%02d%02d", &y, &m, &d, &H, &M, &S );

		m_tm.wYear = ( WORD )y;
		m_tm.wMonth = ( WORD )m;
		m_tm.wDay = ( WORD )d;
		m_tm.wHour = ( WORD )H;
		m_tm.wMinute = ( WORD )M;
		m_tm.wSecond = ( WORD )S;

		return ret;
	}

	int time_impl::set_time_name_ymd( const char * lpszTimeStr )
	{
		int ret = 0;

		memset( &m_tm, 0, sizeof( m_tm ) );

		int y = 0;
		int m = 0;
		int d = 0;

		sscanf_s( lpszTimeStr, "%04d%02d%02d", &y, &m, &d );

		m_tm.wYear = ( WORD )y;
		m_tm.wMonth = ( WORD )m;
		m_tm.wDay = ( WORD )d;

		return ret;
	}

    int time_impl::set_wall_time_s( xos_i64 tm_s )
    {
        int ret = 0;

		tm temptm = { 0 };
        localtime_s( &temptm, &tm_s );
        SYSTEMTIME st = 
        {
            ( WORD )(1900 + temptm.tm_year),
            ( WORD )(1 + temptm.tm_mon),
            ( WORD ) temptm.tm_wday,
            ( WORD ) temptm.tm_mday,
            ( WORD ) temptm.tm_hour,
            ( WORD ) temptm.tm_min,
            ( WORD ) temptm.tm_sec,
            ( WORD ) 0 };
		std::memcpy( &m_tm, &st, sizeof( st ) );

        return ret;
    }

    int time_impl::set_milli_second( int tm_ms )
    {
        int ret = 0;
        m_tm.wMilliseconds = ( WORD )tm_ms;
        return ret;
    }

    int time_impl::set_year( int tm_y )
    {
        int ret = 0;
        m_tm.wYear = tm_y;
        return ret;
    }

    int time_impl::set_month( int tm_m )
    {
        int ret = 0;
        m_tm.wMonth = tm_m;
        return ret;
    }

    int time_impl::set_day( int tm_d )
    {
        int ret = 0;
        m_tm.wDay = tm_d;
        return ret;
    }

    int time_impl::set_hour( int tm_h )
    {
        int ret = 0;
        m_tm.wHour = tm_h;
        return ret;
    }

    int time_impl::set_minute( int tm_m )
    {
        int ret = 0;
        m_tm.wMinute = tm_m;
        return ret;
    }

    int time_impl::set_second( int tm_s )
    {
        int ret = 0;
        m_tm.wSecond = tm_s;
        return ret;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 

	// 
	// calculate time difference. unit : 1 / 1000 second
	// 
	int time_impl::diffrent( i_time * pLastTime, xos_i64 * lpulDif )
	{
		int nRet = 0;

		time_impl * pImpl = static_cast< time_impl * >( pLastTime );

		if( !lpulDif || !pLastTime )
		{
			nRet = 1;
		}

		if( 0 == nRet )
		{
			LARGE_INTEGER l_cur = { 0 }, l_last = { 0 };
			FILETIME cur = { 0 }, last = { 0 };

			SystemTimeToFileTime( &pImpl->m_tm, &last );
			SystemTimeToFileTime( &m_tm, &cur );

			l_last.HighPart = last.dwHighDateTime;
			l_last.LowPart = last.dwLowDateTime;

			l_cur.HighPart = cur.dwHighDateTime;
			l_cur.LowPart = cur.dwLowDateTime;

			*lpulDif = (xos_i64)( ( l_cur.QuadPart - l_last.QuadPart ) / 10000 );
		}

		return nRet;
	}
} // xos
